using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GZ.DB.Entity.wcs_hy;
using GZ.DB.IRepository.wcs_hy;
using GZ.DB.Repository.wcs_hy;
using GZ.Common.Data;

namespace GZ.Projects.WCS_YB
{
	/// <summary>
	/// 设备状态检查结果
	/// </summary>
	public class DeviceStatusResult
	{
		public bool IsReady { get; set; }
		public string StatusMessage { get; set; }
	}

	/// <summary>
	/// 任务下发结果
	/// </summary>
	public class TaskDispatchResult
	{
		public bool Success { get; set; }
		public string Message { get; set; }
	}

	/// <summary>
	/// 前置任务执行结果
	/// </summary>
	public class PreTaskResult
	{
		public bool HasPreTask { get; set; }
		public bool Success { get; set; }
		public string Message { get; set; }
	}

	/// <summary>
	/// 出库口状态检查结果
	/// </summary>
	public class OutletStatusResult
	{
		public bool IsAvailable { get; set; }
		public string Message { get; set; }
	}

	/// <summary>
	/// 任务调度辅助类
	/// </summary>
	public class TaskDispatchHelper
	{
		private Conn Conn = new Conn();

		/// <summary>
		/// 检查设备状态
		/// </summary>
		/// <param name="suffixName">设备名称</param>
		/// <param name="isDoubleStation">是否为双工位堆垛机，默认为单工位</param>
		/// <returns>设备状态检查结果</returns>
		public DeviceStatusResult CheckDeviceStatus(string suffixName, bool isDoubleStation = false)
		{
			try
			{
				string modeValue = Conn.YBRedis.GetValue($"{suffixName}.plc_auto"); //设备模式 1 联机自动;2手动;3半自动;4维修;
				string faultValue = Conn.YBRedis.GetValue($"{suffixName}.plc_alarm_Code");//报警 1 正常 2 有报警
				string stateValue = Conn.YBRedis.GetValue($"{suffixName}.plc_state");//1正常 允许下发任务
				string loadedValueS1 = Conn.YBRedis.GetValue($"{suffixName}.plc_loaded1");//载货台有无货物 1有货 0 无货
				string loadedValueS2 = Conn.YBRedis.GetValue($"{suffixName}.plc_loaded2");//载货台有无货物 1有货 0 无货
				string memResendS1 = Conn.YBRedis.GetValue($"MEM.{suffixName}_Resend_S1");//内存重发标志 1 重发 0 不重发
				string memResendS2 = Conn.YBRedis.GetValue($"MEM.{suffixName}_Resend_S2");//内存重发标志 1 重发 0 不重发

				// 检查各项状态
				if (modeValue != "1")
				{
					return new DeviceStatusResult { IsReady = false, StatusMessage = $"设备模式不正确:[{modeValue}]，需要联机自动模式" };
				}
				if (stateValue != "1")
				{
					return new DeviceStatusResult { IsReady = false, StatusMessage = $"设备状态不正常:[{stateValue}]" };
				}
				if (faultValue != "1")
				{
					return new DeviceStatusResult { IsReady = false, StatusMessage = $"设备有报警:[{faultValue}]" };
				}

				// 根据是否为双工位检查载货台状态
				if (isDoubleStation)
				{
					if (loadedValueS1 != "0" || loadedValueS2 != "0")
					{
						return new DeviceStatusResult { IsReady = false, StatusMessage = $"载货台有货物:[{loadedValueS1},{loadedValueS2}]" };
					}
					if (memResendS1 != "0" || memResendS2 != "0")
					{
						return new DeviceStatusResult { IsReady = false, StatusMessage = $"堆垛机有重分标记:[{memResendS1},{memResendS2}]" };
					}
				}
				else
				{
					// 单工位只检查第一个载货台
					if (loadedValueS1 != "0")
					{
						return new DeviceStatusResult { IsReady = false, StatusMessage = $"载货台有货物:[{loadedValueS1}]" };
					}
					if (memResendS1 != "0")
					{
						return new DeviceStatusResult { IsReady = false, StatusMessage = $"堆垛机有重分标记:[{memResendS1}]" };
					}
				}

				return new DeviceStatusResult { IsReady = true, StatusMessage = "设备状态正常" };
			}
			catch (Exception ex)
			{
				return new DeviceStatusResult { IsReady = false, StatusMessage = $"检查设备状态异常：{ex.Message}" };
			}
		}

		/// <summary>
		/// 统一的任务下发到Redis并更新数据库的方法
		/// </summary>
		/// <param name="stack">堆垛机任务</param>
		/// <param name="commandType">命令类型</param>
		/// <param name="taskTypeDesc">任务类型描述</param>
		/// <param name="msg">输出消息</param>
		/// <returns>是否成功</returns>
		public bool SendTaskToRedisAndUpdateDB(StackerTaskEntity stack, string commandType, string taskTypeDesc,
		                                       out string msg)
		{
			msg = "";
			try
			{
				string num = stack.DeviceNo.Substring(stack.DeviceNo.Length - 2);

				// 下发任务到Redis
				StackerSendToRedis sendToRedis = new StackerSendToRedis();
				bool sendResult = sendToRedis.SendTask_SingleStation(commandType, stack, out string error);

				if (sendResult)
				{
					msg += $"\r\n\t{taskTypeDesc}任务下发成功:{stack.TrayCode};{DateTime.Now:yyyy/MM/dd HH:mm:ss:fff}";

					// 更新任务状态
					stack.TaskState = "Send";
					stack.TaskStartTime = DateTime.Now;
					stack.LastUpdatedTime = DateTime.Now;
					
					DBOpeation dbOpeation = new DBOpeation();
					bool dbResult = false;
					if (stack.DeviceTaskType == "ST_Out" || stack.DeviceTaskType == "ST_Move")
					{
						SystemSynchronizationEntity systemSynchronization = new SystemSynchronizationEntity();
						systemSynchronization.syn_direction = 2;
						systemSynchronization.syn_status = 0;
						systemSynchronization.ope_type = "1"; //出库任务上报任务开始
						systemSynchronization.task_no = stack.TaskNo;
						systemSynchronization.cur_pos = stack.FromLocalNo; 
						systemSynchronization.ope_time = DateTime.Now;
						
						dbResult = dbOpeation.UpdateStackerTask(stack, out string errorMsg);
						msg += $"\r\n\t更新任务信息结束，写入结果：{(dbResult ? "成功" : "失败")}" + errorMsg;
					}
					else
					{
						dbResult = dbOpeation.UpdateStackerTask(stack, out string errorMsg);
						msg += $"\r\n\t更新任务信息结束，写入结果：{(dbResult ? "成功" : "失败")}" + errorMsg;
					}
					
					// 更新内存记录
					if (dbResult)
					{
						bool memResult = StackMemTaskInfo(stack.DeviceTaskNo,stack.TrayCode, stack.FromLocalNo, stack.ToLocalNo, num);
						if (memResult)
						{
							return true;
						}
						else
						{
							msg += $"\r\n\t内存记录更新失败，请检查Redis连接";
						}
					}
				}
				else
				{
					msg += $"\r\n\t{taskTypeDesc}任务下发失败：{error}";
				}

				return false;
			}
			catch (Exception ex)
			{
				msg += $"\r\n\t{taskTypeDesc}任务下发异常：{ex.Message}";
				return false;
			}
		}

		/// <summary>
		/// 执行任务下发
		/// </summary>
		/// <param name="stackerTask">堆垛机任务</param>
		/// <returns>任务下发结果</returns>
		public TaskDispatchResult ExecuteTaskDispatch(StackerTaskEntity stackerTask)
		{
			string handleMsg = "";
			bool success = false;

			try
			{
				//判断任务类型
				switch (stackerTask.TaskType)
				{
					case "ST_In":
						success = TaskSend_In(stackerTask, out handleMsg);
						break;
					case "ST_Move":
						success = TaskSend_Move(stackerTask, out handleMsg);
						break;
					case "ST_Out":
						success = TaskSend_Out(stackerTask, out handleMsg);
						break;
					default:
						handleMsg = $"\r\n\t不支持的任务类型[{stackerTask.TaskType}]";
						success = false;
						break;
				}

				return new TaskDispatchResult { Success = success, Message = handleMsg };
			}
			catch (Exception ex)
			{
				handleMsg = $"\r\n\t任务下发异常：{ex.Message}";
				return new TaskDispatchResult { Success = false, Message = handleMsg };
			}
		}

		/// <summary>
		/// 入库任务下发
		/// </summary>
		/// <param name="stack">堆垛机任务</param>
		/// <param name="inMsg">输出消息</param>
		/// <returns>是否成功</returns>
		public bool TaskSend_In(StackerTaskEntity stack, out string inMsg)
		{
			inMsg = "";
			try
			{
				string tagName = "";

				// 判断是一楼还是二楼
				if (stack.FromLocalNo.StartsWith("10"))
				{
					tagName = "TPPLC_1";  //1楼
				}
				else if (stack.FromLocalNo.StartsWith("20"))
				{
					tagName = "TPPLC_2"; //2楼
				}
				else
				{
					inMsg = $"\r\n\t[入库]任务下发异常,入库任务{stack.FromLocalNo}编号异常";
					return false;
				}
				// 检查到位输送线携带的条码
				string fromLocalNoContNo = Conn.YBRedis.GetValue($"{tagName}.PLC_CONTNO_{stack.FromLocalNo}");
				if (fromLocalNoContNo == stack.TrayCode)
				{
					// 入库任务下发
					return SendTaskToRedisAndUpdateDB(stack, "1", "[入库]", out inMsg);
				}
				else
				{
					inMsg = $"\r\n\t[入库]任务下发异常,入库口输送线{stack.FromLocalNo}携带的条码与任务不匹配";
					return false;
				}
			}
			catch (Exception e)
			{
				inMsg = $"\r\n\t[入库]任务下发异常：{e.Message}";
				Conn.YBLog.Error(1, $"[{stack.DeviceNo}入库任务下发异常]", 1, e.ToString());
				return false;
			}
		}

		/// <summary>
		/// 移库任务下发
		/// </summary>
		/// <param name="stack">堆垛机任务</param>
		/// <param name="moveMsg">输出消息</param>
		/// <returns>是否成功</returns>
		public bool TaskSend_Move(StackerTaskEntity stack, out string moveMsg)
		{
			moveMsg = "";
			try
			{
				// 移库任务直接下发，无需额外检查
				return SendTaskToRedisAndUpdateDB(stack, "1", "[移库]", out moveMsg);
			}
			catch (Exception e)
			{
				moveMsg = $"\r\n\t[移库]任务下发异常：{e.Message}";
				Conn.YBLog.Error(1, $"[{stack.DeviceNo}移库任务下发异常]", 1, e.ToString());
				return false;
			}
		}

		/// <summary>
		/// 出库任务下发
		/// </summary>
		/// <param name="stack">堆垛机任务</param>
		/// <param name="outMsg">输出消息</param>
		/// <returns>是否成功</returns>
		public bool TaskSend_Out(StackerTaskEntity stack, out string outMsg)
		{
			outMsg = "";
			try
			{
				IStackerTaskRepository stackerRepo = new StackerTaskRepository();
				// 检查是否有前置移库任务需要先执行
				var preTask = stackerRepo.FindEntity(t => t.TaskNo == stack.TaskNo_Per);
				if (preTask != null)
				{
					bool preTaskResult = TaskSend_Move(preTask, out string handleMsg);
					outMsg += $"\r\n\t[出库]下发任务前置移库任务执行{(preTaskResult ? "完毕" : "失败")}:{stack.TrayCode};{DateTime.Now:yyyy/MM/dd HH:mm:ss:fff}" + handleMsg;
					return preTaskResult;
				}

				// 检查出库口状态
				//var outletStatus = CheckOutletStatus(stack.ToLocalNo);
				string tagName = "";
				// 判断是一楼还是二楼
				if (stack.ToLocalNo.StartsWith("10"))
				{
					tagName = "TPPLC_1";  //1楼
				}
				else if (stack.ToLocalNo.StartsWith("20"))
				{
					tagName = "TPPLC_2"; //2楼
				}
				else
				{
					outMsg += $"\r\n\t[出库]出库口任务异常:{stack.TrayCode}的终点位置不正确;{DateTime.Now:yyyy/MM/dd HH:mm:ss:fff}";
					return false;
				}

				// 检查出库口光电状态
				bool toLocalNoState = Conn.YBRedis.GetValue($"{tagName}.PLC_STATE_{stack.ToLocalNo}") == "1";
				if (!toLocalNoState)
				{
					outMsg += $"\r\n\t[出库]出库口光电不满足:{stack.TrayCode}的终点光电未给可出信号;{DateTime.Now:yyyy/MM/dd HH:mm:ss:fff}";
					return false;
				}

				// 执行出库任务下发
				return SendTaskToRedisAndUpdateDB(stack, "1", "[出库]", out outMsg);
			}
			catch (Exception ex)
			{
				outMsg = $"\r\n\t[出库]任务下发异常：{ex.Message}";
				Conn.YBLog.Error(1, $"[{stack.DeviceNo}出库任务下发异常]", 1, ex.ToString());
				return false;
			}
		}

		/// <summary>
		/// 堆垛机内存任务记录
		/// </summary>
		/// <param name="deviceTaskNo">设备任务编号</param>
		/// <param name="contNum">托盘编码</param>
		/// <param name="curNum">当前位置</param>
		/// <param name="toNum">目标位置</param>
		/// <param name="num">堆垛机编号</param>
		/// <returns>是否成功</returns>
		public bool StackMemTaskInfo(string deviceTaskNo ,string contNum, string curNum, string toNum, string num)
		{
			try
			{
				string setQueue = $"MEMQueue";
				string groupName = $"MEM.TC{num}_INFO";

				GZ.Modular.Redis.WriteGroupEntity group = new GZ.Modular.Redis.WriteGroupEntity
				{
					groupName = groupName,
					queueStatus = 1,
					queueTime = DateTime.Now,
					writeList = new List<GZ.Modular.Redis.ParamData>
					{
						new GZ.Modular.Redis.ParamData
						{
							paramName = $"MEM.TC{num}_DeviceTaskNo",
							paramValue = deviceTaskNo
						},
						new GZ.Modular.Redis.ParamData
						{
							paramName = $"MEM.TC{num}_ContNo",
							paramValue = contNum
						},
						new GZ.Modular.Redis.ParamData
						{
							paramName = $"MEM.TC{num}_CurPos",
							paramValue = curNum
						},
						new GZ.Modular.Redis.ParamData
						{
							paramName = $"MEM.TC{num}_ToPos",
							paramValue = toNum
						}
					}
				};
				bool result = Conn.YBRedis.SetQueue(group, setQueue, "", "");
				return result;
			}
			catch (Exception e)
			{
				Conn.YBLog.Error(1, $"[堆垛机MEM记录失败[TC{num}]]", 1, e.ToString());
				return false;
			}
		}
	}
}